home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Camelot / Camelot 043 (1989-06)(Swedish User Group of Amiga)(SE)(PD)[WB].zip / Camelot 043 (1989-06)(Swedish User Group of Amiga)(SE)(PD)[WB].adf / Glib / k5.c < prev    next >
C/C++ Source or Header  |  1989-03-16  |  12KB  |  601 lines

  1. /*
  2.  * GLIB - a Generic LIBrarian and editor for synths
  3.  *
  4.  * Kawai K-5 Librarian - handles SINGLE and MULTI patches.
  5.  * Functions are annotated if they work for SINGLE, MULTI, or both kinds.
  6.  * Full editing not implemented - there are zillions of parameters,
  7.  * and the huge LCD on the K-5 is actually quite easy to read and use.
  8.  *
  9.  * Alan Bland - att!druwy!mab
  10.  */
  11.  
  12. #define OVERLAY2
  13.  
  14. #include "glib.h"
  15.  
  16. #define K5SINGLE    0
  17. #define K5MULTI        1
  18. #define K5MAGIC        0x5a3c
  19.  
  20. #define NERRS        5
  21.  
  22. extern char *visnum();
  23.  
  24. /* This array contains arbitrary screen labels (SINGLE) */
  25. struct labelinfo Lk5sin[] = {
  26.  3,10,"Sorry, no edit capability implemented for the K-5 yet.",
  27. 15,2,"+-------------------------+--------------+",
  28. 16,2,"|Space = Play Note",16,28,"| Auto-Note    |",
  29. 17,2,"|",17,28,"|",17,43,"|",
  30. 18,2,"|h = left   q = quit      |Pitch",18,43,"|",
  31. 19,2,"|j = down   N = Set Name  |Volume",19,43,"|",
  32. 20,2,"|k = up     J = Decrement |Duration      |",
  33. 21,2,"|l = right  K = Increment |Channel       |",
  34. 22,2,"|",22,28,"|",22,43,"|",
  35. 23,2,"+-------------------------+--------------+",
  36. -1,-1,NULL
  37. };
  38.  
  39. /* This array defines all the editable parameters. (SINGLE) */
  40. struct paraminfo Pk5sin[] = {
  41. "autopitch",    NULL,    -1,-1, 18, 38, visnum,         0, 127, 60, 0,
  42. "autovol",    NULL,    -1,-1, 19, 38, visnum,         0, 127, 63, 0,
  43. "autodur",    NULL,    -1,-1, 20, 38, visnum,         1,  20,  5, 0,
  44. "autochan",    NULL,    -1,-1, 21, 38, visnum,         1,  16,  1, 0,
  45.  
  46. NULL,        NULL,    -1,-1, -1, -1, visnum,         0,   0, 0, 0
  47. };
  48.  
  49. /* This array contains arbitrary screen labels (MULTI) */
  50. struct labelinfo Lk5mul[] = {
  51.  3,10,"Sorry, no edit capability implemented for the K-5 yet.",
  52. 15,2,"+-------------------------+--------------+",
  53. 16,2,"|Space = Play Note",16,28,"| Auto-Note    |",
  54. 17,2,"|",17,28,"|",17,43,"|",
  55. 18,2,"|h = left   q = quit      |Pitch",18,43,"|",
  56. 19,2,"|j = down   N = Set Name  |Volume",19,43,"|",
  57. 20,2,"|k = up     J = Decrement |Duration      |",
  58. 21,2,"|l = right  K = Increment |Channel       |",
  59. 22,2,"|",22,28,"|",22,43,"|",
  60. 23,2,"+-------------------------+--------------+",
  61. -1,-1,NULL
  62. };
  63.  
  64. /* This array defines all the editable parameters. (MULTI) */
  65. struct paraminfo Pk5mul[] = {
  66. "autopitch",    NULL,    -1,-1, 18, 38, visnum,         0, 127, 60, 0,
  67. "autovol",    NULL,    -1,-1, 19, 38, visnum,         0, 127, 63, 0,
  68. "autodur",    NULL,    -1,-1, 20, 38, visnum,         1,  20,  5, 0,
  69. "autochan",    NULL,    -1,-1, 21, 38, visnum,         1,  16,  1, 0,
  70.  
  71. NULL,        NULL,    -1,-1, -1, -1, visnum,         0,   0, 0, 0
  72. };
  73.  
  74. /*
  75.  * k5vnum
  76.  *
  77.  * Convert a voice number (0 to 47) to the string displayed in the
  78.  * librarian (A1-D12)  (SINGLE and MULTI)
  79.  */
  80. char *
  81. k5vnum(n)
  82. register int n;
  83. {
  84.     static char v[4];
  85.  
  86.     if ( n < 0 || n > 47 )
  87.         return("??");
  88.  
  89.     sprintf(v, "%c%d", n/12 + 'A', n%12 + 1);
  90.     return(v);
  91. }
  92.  
  93. /*
  94.  * k5numv
  95.  *
  96.  * Convert an alphanumeric voice number (A1-D12) to internal
  97.  * format (0 - 47).  (SINGLE and MULTI)
  98.  */
  99. k5numv(n)
  100. register char *n;
  101. {
  102.     register int v,j;
  103.  
  104.     /* first better be [a-dA-D] */
  105.     *n = toupper(*n);
  106.     if (*n == 'A' || *n == 'B' || *n == 'C' || *n == 'D') {
  107.         v = 12 * (*n - 'A');
  108.     } else {
  109.         return(-1);
  110.     }
  111.  
  112.     /* followed by 1-12 */
  113.     j = atoi(++n);
  114.     if (j<1 || j>12) return(-1);
  115.     return v + j - 1;
  116. }
  117.  
  118. /*
  119.  * k5sindin
  120.  *
  121.  * Take library bank 'data' and stuff values in the P array, by using
  122.  * the setval function.
  123.  */
  124. k5sindin(data)
  125. char *data;
  126. {
  127.     /* We set the 'auto-note' channel upon entry */
  128.     setval("autochan",Channel);
  129. }
  130.  
  131. /*
  132.  * k5sindout
  133.  *
  134.  * Take (possibly changed) parameters values out of the P array and
  135.  * put them back into the library bank 'data'.
  136.  */
  137. k5sindout(data)
  138. char *data;
  139. {
  140.     /* If the autochan parameter has changed, update Channel */
  141.     Channel = getval("autochan");
  142. }
  143.  
  144. /*
  145.  * k5muldin
  146.  *
  147.  * Take library bank 'data' and stuff values in the P array, by using
  148.  * the setval function.
  149.  */
  150. k5muldin(data)
  151. char *data;
  152. {
  153.     /* We set the 'auto-note' channel upon entry */
  154.     setval("autochan",Channel);
  155. }
  156.  
  157. /*
  158.  * k5muldout
  159.  *
  160.  * Take (possibly changed) parameters values out of the P array and
  161.  * put them back into the library bank 'data'.
  162.  */
  163. k5muldout(data)
  164. char *data;
  165. {
  166.     /* If the autochan parameter has changed, update Channel */
  167.     Channel = getval("autochan");
  168. }
  169.  
  170. /*
  171.  * k5sinnof
  172.  *
  173.  * Return a pointer to the voice name buried in library bank data. (SINGLE)
  174.  */
  175. char *
  176. k5sinnof(data)
  177. register char *data;
  178. {
  179.     static char currbuff[9];
  180.     register char *p;
  181.     register int m;
  182.  
  183.     p = currbuff;
  184.     for ( m=0; m<16; m+=2 )
  185.         *p++ = (data[m]<<4) | data[m+1];
  186.     *p = '\0';
  187.     return(currbuff);
  188. }
  189.  
  190. /*
  191.  * k5nameok
  192.  *
  193.  * Convert an ascii string to the ascii subset used for K5 names.
  194.  */
  195. char*
  196. k5nameok(name)
  197. char *name;
  198. {
  199.     static char okname[9];
  200.     register int m;
  201.  
  202.     for (m=0; m<9 && name[m]; ++m) {
  203.         okname[m] = toupper(name[m]);
  204.         if (!isalnum(okname[m])) {
  205.             switch (okname[m]) {
  206.             case '-': case ':': case '/': case '*': case '?':
  207.             case '!': case '#': case '&': case '(': case ')':
  208.             case '"': case '+': case '.': case '=': case ' ':
  209.                 break;
  210.             default:
  211.                 okname[m] = ' ';
  212.                 break;
  213.             }
  214.         }
  215.     }
  216.     okname[m] = '\0';
  217.     return okname;
  218. }
  219.  
  220. /*
  221.  * k5sinsnof
  222.  *
  223.  * Set the voice name buried in data to name. (SINGLE)
  224.  */
  225. k5sinsnof(data,name)
  226. char *data;
  227. char *name;
  228. {
  229.     register char *p;
  230.     register int m;
  231.  
  232.     for ( p=k5nameok(name),m=0; *p!='\0' && m<17; p++,m+=2 ) {
  233.         data[m] = (*p & 0xf0) >> 4;
  234.         data[m+1] = *p & 0x0f;
  235.     }
  236.     for ( ; m<17; m+=2 ) {
  237.         data[m] = (' ' & 0xf0) >> 4;
  238.         data[m+1] = ' ' & 0x0f;
  239.     }
  240. }
  241. /*
  242.  * k5mulnof
  243.  *
  244.  * Return a pointer to the voice name buried in library bank data. (MULTI)
  245.  */
  246. char *
  247. k5mulnof(data)
  248. char *data;
  249. {
  250.     static char currbuff[9];
  251.     register char *p;
  252.     register int m;
  253.  
  254.     p = currbuff;
  255.     for ( m=0; m<16; m+=2 )
  256.         *p++ = (data[m+330]<<4) | data[m+331];
  257.     *p = '\0';
  258.     return(currbuff);
  259. }
  260.  
  261. /*
  262.  * k5mulsnof
  263.  *
  264.  * Set the voice name buried in data to name. (MULTI)
  265.  */
  266. k5mulsnof(data,name)
  267. char *data;
  268. char *name;
  269. {
  270.     char *p;
  271.     int m;
  272.  
  273.     for ( p=k5nameok(name),m=0; *p!='\0' && m<17; p++,m+=2 ) {
  274.         data[m+330] = (*p & 0xf0) >> 4;
  275.         data[m+331] = *p & 0x0f;
  276.     }
  277.     for ( ; m<17; m+=2 ) {
  278.         data[m+330] = (' ' & 0xf0) >> 4;
  279.         data[m+331] = ' ' & 0x0f;
  280.     }
  281. }
  282.  
  283. /*
  284.  * k5sbulk
  285.  *
  286.  * common function to send all voices to the K-5 (SINGLE and MULTI)
  287.  */
  288. k5sbulk(data, which)
  289. char *data;
  290. int which;    /* K5SINGLE or K5MULTI */
  291. {
  292.     int n, err = 0;
  293.     message("");
  294.     for (n=0; n<Nvoices; ++n) {
  295.         for (err=0; err<NERRS; ++err) {
  296.             if (k5sone(n, &(VOICEBYTE(data,n,0)), which ) == 0 ) {
  297.                 windputc('+');
  298.                 windrefresh();
  299.                 break;
  300.             }
  301.             windputc('-');
  302.             windrefresh();
  303.         }
  304.         if (err == NERRS) return(1);
  305.     }
  306.     return(0);
  307. }
  308.  
  309. /*
  310.  * k5sinsbulk
  311.  *
  312.  * send all voices to the K-5 (SINGLE)
  313.  */
  314. k5sinsbulk(data)
  315. char *data;
  316. {
  317.     return k5sbulk(data, K5SINGLE);
  318. }
  319.  
  320. /*
  321.  * k5mulsbulk
  322.  *
  323.  * send all voices to the K-5 (MULTI)
  324.  */
  325. k5mulsbulk(data)
  326. char *data;
  327. {
  328.     return k5sbulk(data, K5MULTI);
  329. }
  330.  
  331. /*
  332.  * k5sinsone
  333.  *
  334.  * send one voice to the K-5 (SINGLE)
  335.  */
  336. k5sinsone(iv, data)
  337. int iv;
  338. char *data;
  339. {
  340.     return k5sone(iv, data, K5SINGLE);
  341. }
  342.  
  343. /*
  344.  * k5mulsone
  345.  *
  346.  * send one voice to the K-5 (MULTI)
  347.  */
  348. k5mulsone(iv, data)
  349. {
  350.     return k5sone(iv, data, K5MULTI);
  351. }
  352.  
  353. /*
  354.  * k5sone
  355.  *
  356.  * common function to send a SINGLE or MULTI voice to the K-5.
  357.  */
  358. k5sone(iv, data, which)
  359. int iv;
  360. register char *data;
  361. int which;    /* K5SINGLE or K5MULTI */
  362. {
  363.     register int i, sum;
  364.     int length;
  365.     int c = 0, ret = 1;
  366.     long begin, toolong;
  367.  
  368.     flushmidi();
  369.  
  370.     length = (which == K5SINGLE) ? 984 : 352;
  371.  
  372.     /* calculate checksum */
  373.     for (sum=0, i=0; i<length-4; ) {
  374.         sum += data[i++] << 4;
  375.         sum += data[i++];
  376.         sum += data[i++] << 12;
  377.         sum += data[i++] << 8;
  378.     }
  379.  
  380.     sum = K5MAGIC - sum;
  381.     data[length-4] = (sum & 0x00f0) >> 4;
  382.     data[length-3] = (sum & 0x000f);
  383.     data[length-2] = (sum & 0xf000) >> 12;
  384.     data[length-1] = (sum & 0x0f00) >> 8;
  385.     
  386.     sendmidi(0xf0);
  387.     sendmidi(0x40);
  388.     sendmidi(Channel-1);
  389.     sendmidi(0x20);
  390.     sendmidi(0x00);
  391.     sendmidi(0x02);
  392.     sendmidi(which);
  393.     sendmidi(iv);
  394.  
  395.     for (i=0; i<length; i++) sendmidi(data[i]);
  396.  
  397.     sendmidi(EOX);
  398.  
  399.     /* read the ack/nack - set up for timeout */
  400.     begin = milliclock();
  401.     toolong = begin + 1000 * TIMEOUT;
  402.  
  403.     /* wait for the acknowledgement */
  404.     while ( milliclock() < toolong ) {
  405.         if ( STATMIDI && (c=(getmidi() & 0xff)) == 0xf0 )
  406.             break;
  407.     }
  408.     if ( c != 0xf0 ) {
  409.         Reason = "Timeout waiting for K-5 response";
  410.         goto getout;
  411.     }
  412.     
  413.     /* third byte after the sysex begin is the result */
  414.     for (i=0; i<3; ) {
  415.         /* wait for midi byte or timeout */
  416.         while ( ! STATMIDI ) {
  417.             if ( milliclock() > toolong ) {
  418.                 Reason = "Timeout waiting for K-5 response";
  419.                 goto getout;
  420.             }
  421.         }
  422.         /* ignore active sensing */
  423.         if ((c = getmidi() & 0xff) != 0xfe) {
  424.             ++i;
  425.         }
  426.     }
  427.  
  428.     /* check the result */
  429.     switch (c) {
  430.     case 0x40:
  431.         ret = 0;
  432.         Reason = "";
  433.         break;
  434.     case 0x41:
  435.         Reason = "K-5 write error";
  436.         break;
  437.     case 0x42:
  438.         Reason = "K-5 write error (protected)";
  439.         break;
  440.     case 0x43:
  441.         Reason = "K-5 write error (no card)";
  442.         break;
  443.     default:
  444.         Reason = "Wierd response (is that really a K-5 you have?)";
  445.         break;
  446.     }
  447.  
  448. getout:
  449.     return(ret);
  450. }
  451.  
  452. k5sinsedit()
  453. {
  454. }
  455.  
  456. k5mulsedit()
  457. {
  458. }
  459.  
  460. /*
  461.  * k5singbulk
  462.  *
  463.  * get all internal SINGLE voices from K-5.
  464.  */
  465. k5singbulk(data)
  466. char *data;
  467. {
  468.     return k5gbulk(data, K5SINGLE);
  469. }
  470.  
  471. /*
  472.  * k5mulgbulk
  473.  *
  474.  * get all internal MULTI voices from K-5.
  475.  */
  476. k5mulgbulk(data)
  477. char *data;
  478. {
  479.     return k5gbulk(data, K5MULTI);
  480. }
  481.  
  482. /*
  483.  * k5gbulk
  484.  *
  485.  * common routine - get all SINGLE or MULTI voices from K-5.
  486.  */
  487. k5gbulk(data, which)
  488. register char *data;
  489. int which;    /* K5SINGLE or K5MULTI */
  490. {
  491.     int c, v, sumerr = 0;
  492.     register int n, i, sum;
  493.     long begin, toolong;
  494.  
  495.     message("");
  496.     flushmidi();
  497.  
  498.     for(v = 0; v < Nvoices; v++) {
  499.  
  500. retry:        
  501.         if (which == K5MULTI) {
  502.             /* i don't know if this is a K-5 or Amiga problem */
  503.             /* but multi patch download seems to need this delay */
  504.             millisleep(500);
  505.         }
  506.         /* request the voice */
  507.         sendmidi(0xf0);
  508.         sendmidi(0x40);
  509.         sendmidi(Channel-1);
  510.         sendmidi(0x00);
  511.         sendmidi(0x00);
  512.         sendmidi(0x02);
  513.         sendmidi(which);
  514.         sendmidi(v);
  515.         sendmidi(EOX);
  516.     
  517.         /* set up for timeout */
  518.         begin = milliclock();
  519.         toolong = begin + 1000 * TIMEOUT;
  520.     
  521.         /* wait for the xf0 byte starting the dump */
  522.         while ( milliclock() < toolong ) {
  523.             if ( STATMIDI && (c=(getmidi() & 0xff)) == 0xf0 )
  524.                 break;
  525.         }
  526.         if ( c != 0xf0 ) {
  527.             Reason = "Timeout waiting for dump from K-5";
  528.             return 1;
  529.         }
  530. /*printf("%02x ", c);*/
  531.         /* skip the next 7 bytes (remainder of sysex header) */
  532.         for (i=0; i<7; ) {
  533.             /* wait for midi byte or timeout */
  534.             while ( ! STATMIDI ) {
  535.                 if ( milliclock() > toolong )
  536.                     goto timeout;
  537.             }
  538.             /* ignore active sensing */
  539.             if ((c = getmidi() & 0xff) != 0xfe) {
  540.                 ++i;
  541. /*printf("%02x ", c);*/
  542.             }
  543.         }
  544.  
  545.         /* read voice data until EOX */
  546.         n = 0;
  547.         while (1) {
  548.             /* wait for midi byte or timeout */
  549.             while ( ! STATMIDI ) {
  550.                 if ( milliclock() > toolong )
  551.                     goto timeout;
  552.             }
  553.             if ((c = getmidi() & 0xff) == 0xfe) {
  554.                 /* ignore active sensing */
  555.                 continue;
  556.             } else if (c == EOX) {
  557.                 /* finished */
  558.                 break;
  559.             } else {
  560.                 /* got a data byte */
  561.                 VOICEBYTE(data,v,n) = c;
  562.                 ++n;
  563.             }
  564.         }
  565. /*printf("got block n=%d\n", n);*/
  566.         /* verify the checksum */
  567.         for (sum=0, i=0; i<n-4; ) {
  568.             sum += data[i++] << 4;
  569.             sum += data[i++];
  570.             sum += data[i++] << 12;
  571.             sum += data[i++] << 8;
  572.         }
  573.  
  574.         sum = K5MAGIC - sum;
  575.         if ((data[n-4] == (sum & 0x00f0) >> 4) &&
  576.             (data[n-3] == (sum & 0x000f)) &&
  577.             (data[n-2] == (sum & 0xf000) >> 12) &&
  578.             (data[n-1] == (sum & 0x0f00) >> 8)) {
  579.             sumerr = 0;
  580.             windputc('+');
  581.         } else {
  582.             /* retry a few times if checksum failed */
  583.             windputc('-');
  584.             if (sumerr++ >= NERRS) {
  585.                 Reason = "Too many checksum errors!";
  586.                 return(1);
  587.             }
  588.             goto retry;
  589.         }
  590.         windrefresh();
  591.  
  592.     } /* go back for another voice */
  593.     Reason = "";
  594.     return(0);
  595.  
  596. timeout:
  597.     Reason = "Timeout while reading!";
  598.     return(1);
  599. }
  600.  
  601.